home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 10 - Networking / NovelNetwar / serial.c < prev    next >
C/C++ Source or Header  |  1995-05-12  |  30KB  |  1,244 lines

  1. #include "NovelNetwar.h"
  2. #include <serial.h>
  3.  
  4.  
  5.  
  6.  
  7. #define SERIALBUFFERSIZE    1024
  8.  
  9. #define ENDPACKETCHAR        0xFF
  10.  
  11.  
  12. enum { NOPORT, MODEM, PRINTER };
  13.  
  14.  
  15.  
  16. static short            inputRefNum,outputRefNum;    // refNums for serial drivers
  17. static char                outputIsOpen,inputIsOpen,doAsynchReceives;    // flags used to keep track of whether the input/output drivers are open, and whether we're supposed to keep posting new asynch receives
  18. static Ptr                serialInputBufferPtr,serialOutputBufferPtr,serialPacketBuffer;    // pointers to our serial buffers
  19. static ParamBlockRec    myWritePB,myReadPB;    // I/O parameter blocks used for our asynch calls
  20. static long                numBytesInPacketBuff;    // guess what this is used to keep track of....
  21. static short            serialSpeed,serialPort;    // used to keep track of speed of port and *which* port we're using
  22. static char                doXOnXOff,doHH;    // flags to keep track of flow control techniques
  23.  
  24.  
  25.  
  26. static asm void mySerialCompletionASMCode(void);
  27. static asm void SerialReadCompletionRoutineASM(void);
  28. static asm void initSerialReadCompletionRoutine(void);
  29. static void SerialReceiveCompletionC(void);
  30. static void CloseSerialDrivers(void);
  31. static void OpenSerialDrivers(void);
  32.  
  33.  
  34.  
  35. //    Initialize our state variables
  36.  
  37. void serialInit(void)
  38. {
  39.     inputRefNum = 0;
  40.     outputRefNum = 0;
  41.     
  42.     outputIsOpen = false;
  43.     inputIsOpen = false;
  44.     
  45.     doAsynchReceives = false;
  46.     
  47.     serialInputBufferPtr = nil;
  48.     serialOutputBufferPtr = nil;
  49.     serialPacketBuffer = nil;
  50.     
  51.     myWritePB.ioParam.ioResult = 0;
  52.     myReadPB.ioParam.ioResult = 0;
  53.     
  54.     numBytesInPacketBuff = 0;
  55.     
  56.     serialSpeed = baud9600;
  57.     doXOnXOff = false;
  58.     doHH = true;
  59.     serialPort = NOPORT;
  60. }
  61.  
  62.  
  63.  
  64. //    Set up our buffers and anything else important
  65.  
  66.  
  67. void serialStartup(void)
  68. {
  69. OSErr        errCode;
  70. SerShk        mySerShk;
  71.  
  72.     
  73.     if (connectionMethod != SERIAL)
  74.     {
  75.         return;
  76.     }
  77.     
  78.     serialInputBufferPtr = NewPtr(SERIALBUFFERSIZE);
  79.     
  80.     errCode = MemError();
  81.     
  82.     if (serialInputBufferPtr == nil || errCode != noErr)
  83.     {
  84.         sprintf(errorMessage,"serialStartup: NewPtr() error %d, cannot allocate storage for serial port input buffer!",(int) errCode);
  85.         
  86.         FatalError(errorMessage);
  87.     }
  88.     
  89.     
  90.     serialOutputBufferPtr = NewPtr(SERIALBUFFERSIZE);
  91.     
  92.     errCode = MemError();
  93.     
  94.     if (serialOutputBufferPtr == nil || errCode != noErr)
  95.     {
  96.         sprintf(errorMessage,"serialStartup: NewPtr() error %d, cannot allocate storage for serial port output buffer!",(int) errCode);
  97.         
  98.         FatalError(errorMessage);
  99.     }
  100.     
  101.     
  102.     serialPacketBuffer = NewPtr(SERIALBUFFERSIZE);
  103.     
  104.     errCode = MemError();
  105.     
  106.     if (serialPacketBuffer == nil || errCode != noErr)
  107.     {
  108.         sprintf(errorMessage,"serialStartup: NewPtr() error %d, cannot allocate storage for serial packet buffer!",(int) errCode);
  109.         
  110.         FatalError(errorMessage);
  111.     }
  112. }
  113.  
  114.  
  115.  
  116.  
  117.  
  118. //    Tidy up before exiting the program....
  119.  
  120. void serialShutdown(void)
  121. {
  122. OSErr        errCode;
  123. long        theTicks;
  124.     
  125.     
  126.     CloseSerialDrivers();
  127.     
  128.     
  129.     if (serialInputBufferPtr != nil)
  130.     {
  131.         DisposePtr(serialInputBufferPtr);
  132.         
  133.         serialInputBufferPtr = nil;
  134.     }
  135.     
  136.     
  137.     if (serialOutputBufferPtr != nil)
  138.     {
  139.         DisposePtr(serialOutputBufferPtr);
  140.         
  141.         serialOutputBufferPtr = nil;
  142.     }
  143.     
  144.     
  145.     if (serialPacketBuffer != nil)
  146.     {
  147.         DisposePtr(serialPacketBuffer);
  148.         
  149.         serialPacketBuffer = nil;
  150.     }
  151. }
  152.  
  153.  
  154.  
  155.  
  156. //    Routine to close serial drivers if they're open
  157.  
  158. static void CloseSerialDrivers(void)
  159. {
  160. OSErr        errCode;
  161. long        theTicks;
  162.  
  163.  
  164.     if (inputIsOpen == true && (serialPort == MODEM || serialPort == PRINTER))
  165.     {
  166.         doAsynchReceives = false;    // make sure the asynch completion routine doesn't queue up any more read calls
  167.         
  168.         errCode = KillIO(inputRefNum);    //    kill outstanding asynch read calls
  169.         
  170.         if (errCode != noErr)
  171.         {
  172.             sprintf(errorMessage,"CloseSerialDriver: KillIO() error %d, problem killing I/O for input serial port!",(int) errCode);
  173.             ErrorAlert(errorMessage);
  174.         }
  175.         
  176.         theTicks = TickCount();    //    wait for pending reads to timeout or complete
  177.         
  178.         while (myReadPB.ioParam.ioResult == 1 && TickCount() < theTicks + 60*60)
  179.         {
  180.         
  181.         }
  182.         
  183.         if (myReadPB.ioParam.ioResult == 1)
  184.         {
  185.             ErrorAlert("CloseSerialDriver: cannot cancel asynch read— system may crash....");
  186.         }
  187.         
  188.         
  189.         SerSetBuf(inputRefNum,serialInputBufferPtr,0);    //    reset original serial buffer
  190.         
  191.         errCode = CloseDriver(inputRefNum);
  192.     
  193.         if (errCode != noErr)
  194.         {
  195.             sprintf(errorMessage,"CloseSerialDriver: CloseDriver() error %d, problem closing input serial port!",(int) errCode);
  196.             ErrorAlert(errorMessage);
  197.         }
  198.         
  199.         inputRefNum = 0;
  200.         inputIsOpen = false;
  201.     }
  202.     
  203.     
  204.     
  205.     //    see the comments above for closing the input serial port-- this is the same sort of thing
  206.     
  207.     if (outputIsOpen == true && (serialPort == MODEM || serialPort == PRINTER))
  208.     {
  209.         errCode = KillIO(outputRefNum);
  210.         
  211.         if (errCode != noErr)
  212.         {
  213.             sprintf(errorMessage,"CloseSerialDriver: KillIO() error %d, problem killing I/O for output serial port!",(int) errCode);
  214.             ErrorAlert(errorMessage);
  215.         }
  216.         
  217.         theTicks = TickCount();
  218.         
  219.         while (myWritePB.ioParam.ioResult == 1 && TickCount() < theTicks + 60*60)
  220.         {
  221.         
  222.         }
  223.         
  224.         if (myWritePB.ioParam.ioResult == 1)
  225.         {
  226.             ErrorAlert("CloseSerialDriver: cannot cancel asynch write— system may crash....");
  227.         }
  228.         
  229.         
  230.         errCode = CloseDriver(outputRefNum);
  231.         
  232.         if (errCode != noErr)
  233.         {
  234.             sprintf(errorMessage,"CloseSerialDriver: CloseDriver() error %d, problem closing output serial port!",(int) errCode);
  235.             ErrorAlert(errorMessage);
  236.         }
  237.         
  238.         outputRefNum = 0;
  239.         outputIsOpen = false;
  240.     }
  241. }
  242.  
  243.  
  244.  
  245.  
  246. //    Open the serial drivers
  247.  
  248. static void OpenSerialDrivers(void)
  249. {
  250. OSErr        errCode;
  251. SerShk        mySerShk;
  252.  
  253.  
  254.     errCode = noErr;
  255.     
  256.     outputIsOpen = false;
  257.     inputIsOpen = false;
  258.     
  259.     //    printer or modem port?
  260.     
  261.     if (serialPort == MODEM)
  262.     {
  263.         errCode = OpenDriver("\p.AOut",&outputRefNum);
  264.         
  265.         if (errCode != noErr)
  266.         {
  267.             sprintf(errorMessage,"OpenSerialDrivers: OpenDriver() error %d, can't open modem port for output!",(int) errCode);
  268.             ErrorAlert(errorMessage);
  269.         }
  270.         
  271.         else
  272.         {
  273.             outputIsOpen = true;
  274.         }
  275.     }
  276.     
  277.     else if (serialPort == PRINTER)
  278.     {
  279.         errCode = OpenDriver("\p.BOut",&outputRefNum);
  280.         
  281.         if (errCode != noErr)
  282.         {
  283.             sprintf(errorMessage,"OpenSerialDrivers: OpenDriver() error %d, can't open printer port for output!",(int) errCode);
  284.             ErrorAlert(errorMessage);
  285.         }
  286.         
  287.         else
  288.         {
  289.             outputIsOpen = true;
  290.         }
  291.     }
  292.     
  293.     
  294.     //    modem or printer port?
  295.     
  296.     if (serialPort == MODEM)
  297.     {
  298.         errCode = OpenDriver("\p.AIn",&inputRefNum);
  299.         
  300.         if (errCode != noErr)
  301.         {
  302.             sprintf(errorMessage,"OpenSerialDrivers: OpenDriver() error %d, can't open modem port for input!",(int) errCode);
  303.             ErrorAlert(errorMessage);
  304.         }
  305.         
  306.         else
  307.         {
  308.             inputIsOpen = true;
  309.         }
  310.     }
  311.     
  312.     else if (serialPort == PRINTER)
  313.     {
  314.         errCode = OpenDriver("\p.BIn",&inputRefNum);
  315.         
  316.         if (errCode != noErr)
  317.         {
  318.             sprintf(errorMessage,"OpenSerialDrivers: OpenDriver() error %d, can't open printer port for input!",(int) errCode);
  319.             ErrorAlert(errorMessage);
  320.         }
  321.         
  322.         else
  323.         {
  324.             inputIsOpen = true;
  325.         }
  326.     }
  327.     
  328.     
  329.     //    if the drivers were opened, then allocate a bigger buffer than the default input buffer
  330.     
  331.     if (outputIsOpen == true)
  332.     {
  333.         if (inputIsOpen == true)
  334.         {
  335.             SerSetBuf(inputRefNum,serialInputBufferPtr,SERIALBUFFERSIZE);
  336.         }
  337.         
  338.         //    also set the drivers characteristics for the output side-- this will automatically be applied to the input side, too
  339.         
  340.         mySerShk.fXOn = doXOnXOff;
  341.         mySerShk.fCTS = doHH;
  342.         mySerShk.errs = 0;
  343.         mySerShk.evts = 0;
  344.         mySerShk.fInX = doXOnXOff;
  345.         mySerShk.fDTR = doHH;
  346.         
  347.         errCode = Control(outputRefNum,14,&mySerShk);
  348.         
  349.         if (errCode != noErr)
  350.         {
  351.             sprintf(errorMessage,"OpenSerialDrivers: Control() error %d, can't set handshaking configuration for input/output serial port!",(int) errCode);
  352.             ErrorAlert(errorMessage);
  353.         }
  354.         
  355.         
  356.         errCode = SerReset(outputRefNum,serialSpeed+data8+noParity+stop10);
  357.         
  358.         if (errCode != noErr)
  359.         {
  360.             sprintf(errorMessage,"OpenSerialDrivers: SerReset() error %d, can't set output serial port speed/data/parity/stopbits!",(int) errCode);
  361.             ErrorAlert(errorMessage);
  362.         }
  363.     }
  364.     
  365.     
  366.     //    I don't know if this is necessary, but what the heck....
  367.     
  368.     if (inputIsOpen == true)
  369.     {
  370.         errCode = SerReset(inputRefNum,serialSpeed+data8+noParity+stop10);
  371.         
  372.         if (errCode != noErr)
  373.         {
  374.             sprintf(errorMessage,"OpenSerialDrivers: SerReset() error %d, can't set input serial port speed/data/parity/stopbits!",(int) errCode);
  375.             ErrorAlert(errorMessage);
  376.         }
  377.     }
  378. }
  379.  
  380.  
  381.  
  382.  
  383. //    This is the messy routine that does that user-interface junk we all hate so much
  384.  
  385. OSErr serialConnectToOpponents(void)
  386. {
  387. OSErr                errCode;
  388. char                tempString[256];
  389. int                    i;
  390. DialogPtr            theDPtr,tempDPtr;
  391. short                itemHit,type;
  392. Handle                theItem;
  393. Rect                tempRect,theTERect;
  394. GrafPtr                oldPort;
  395. EventRecord            theEvent;
  396. SerShk                mySerShk;
  397. TEHandle            theTEHandle;
  398. short                oldFont,oldSize;
  399. ParamBlockRec        myPBRec;
  400. char                theChar;
  401. long                numCharsInBuff;
  402. char                *srcPtr,*destPtr;
  403. short                selStart,selEnd;
  404. char                doLocalEcho;
  405.  
  406.     
  407.     theTEHandle = nil;
  408.     theDPtr = nil;
  409.     oldPort = nil;
  410.     errCode = noErr;
  411.     doLocalEcho = true;
  412.     
  413.     GetPort(&oldPort);
  414.     
  415.     InitCursor();
  416.     
  417.     //    Show the pretty dialog box
  418.     
  419.     theDPtr = GetNewDialog(SERIALDLOG,nil,(WindowPtr) -1L);
  420.     
  421.     errCode = ResError();
  422.     
  423.     if (errCode != noErr || theDPtr == nil)
  424.     {
  425.         sprintf(errorMessage,"serialConnectToOpponents: GetNewDialog() error %d, can't open dialog!",errCode);
  426.         ErrorAlert(errorMessage);
  427.         goto EXITPOINT;
  428.     }
  429.     
  430.     
  431.     
  432.     SetPort(theDPtr);
  433.     
  434.     //    adjust the appearance of the dialog's controls, etc.
  435.     
  436.     ((DialogPeek) theDPtr)->aDefItem = -1;
  437.     
  438.     if (serialPort == MODEM)
  439.     {
  440.         GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  441.         SetControlValue((ControlHandle) theItem,1);
  442.         GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  443.         SetControlValue((ControlHandle) theItem,0);
  444.         GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  445.         SetControlValue((ControlHandle) theItem,0);
  446.     }
  447.     
  448.     else if (serialPort == PRINTER)
  449.     {
  450.         GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  451.         SetControlValue((ControlHandle) theItem,0);
  452.         GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  453.         SetControlValue((ControlHandle) theItem,1);
  454.         GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  455.         SetControlValue((ControlHandle) theItem,0);
  456.     }
  457.     
  458.     else
  459.     {
  460.         GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  461.         SetControlValue((ControlHandle) theItem,0);
  462.         GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  463.         SetControlValue((ControlHandle) theItem,0);
  464.         GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  465.         SetControlValue((ControlHandle) theItem,1);
  466.     }
  467.     
  468.     
  469.     if (serialSpeed == baud19200)
  470.     {
  471.         GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  472.         SetControlValue((ControlHandle) theItem,0);
  473.         GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  474.         SetControlValue((ControlHandle) theItem,0);
  475.         GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  476.         SetControlValue((ControlHandle) theItem,1);
  477.     }
  478.     
  479.     else if (serialSpeed == baud9600)
  480.     {
  481.         GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  482.         SetControlValue((ControlHandle) theItem,0);
  483.         GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  484.         SetControlValue((ControlHandle) theItem,1);
  485.         GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  486.         SetControlValue((ControlHandle) theItem,0);
  487.     }
  488.     
  489.     else
  490.     {
  491.         GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  492.         SetControlValue((ControlHandle) theItem,1);
  493.         GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  494.         SetControlValue((ControlHandle) theItem,0);
  495.         GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  496.         SetControlValue((ControlHandle) theItem,0);
  497.     }
  498.     
  499.     
  500.     if (doXOnXOff == true)
  501.     {
  502.         GetDItem(theDPtr, 8, &type, &theItem, &tempRect);
  503.         SetControlValue((ControlHandle) theItem,1);
  504.     }
  505.     
  506.     else
  507.     {
  508.         GetDItem(theDPtr, 8, &type, &theItem, &tempRect);
  509.         SetControlValue((ControlHandle) theItem,0);
  510.     }
  511.     
  512.     
  513.     if (doHH == true)
  514.     {
  515.         GetDItem(theDPtr, 9, &type, &theItem, &tempRect);
  516.         SetControlValue((ControlHandle) theItem,1);
  517.     }
  518.     
  519.     else
  520.     {
  521.         GetDItem(theDPtr, 9, &type, &theItem, &tempRect);
  522.         SetControlValue((ControlHandle) theItem,0);
  523.     }
  524.     
  525.     
  526.     if (doLocalEcho == true)
  527.     {
  528.         GetDItem(theDPtr, 17, &type, &theItem, &tempRect);
  529.         SetControlValue((ControlHandle) theItem,1);
  530.     }
  531.     
  532.     else
  533.     {
  534.         GetDItem(theDPtr, 17, &type, &theItem, &tempRect);
  535.         SetControlValue((ControlHandle) theItem,0);
  536.     }
  537.     
  538.     
  539.     //    create a TextEdit record for typing and responses to show in
  540.     
  541.     GetDItem(theDPtr, 16, &type, &theItem, &theTERect);
  542.     InsetRect(&theTERect,5,5);
  543.     
  544.     oldFont = (*theDPtr).txFont;
  545.     oldSize = (*theDPtr).txSize;
  546.     
  547.     TextFont(courier);
  548.     TextSize(10);
  549.     
  550.     theTEHandle = TENew(&theTERect,&theTERect);
  551.  
  552.     TextFont(oldFont);
  553.     TextSize(oldSize);
  554.     
  555.     if (theTEHandle == nil)
  556.     {
  557.         sprintf(errorMessage,"serialConnectToOpponents: can't allocate TextEdit record!");
  558.         ErrorAlert(errorMessage);
  559.         
  560.         errCode = NOTEXTEDITREC;
  561.         
  562.         goto EXITPOINT;
  563.     }
  564.     
  565.     theTERect.bottom = (*theTEHandle)->destRect.top + (((*theTEHandle)->destRect.bottom - (*theTEHandle)->destRect.top)/(*theTEHandle)->lineHeight)*(*theTEHandle)->lineHeight;
  566.     (*theTEHandle)->destRect = theTERect;
  567.     (*theTEHandle)->viewRect = theTERect;
  568.     
  569.     TEActivate(theTEHandle);
  570.     
  571.     TEAutoView(true,theTEHandle);
  572.     
  573.     //    now show the darn thing
  574.     
  575.     CenterWindow(theDPtr);
  576.     ShowWindow(theDPtr);
  577.     
  578.     
  579.     do 
  580.     {
  581.         itemHit = 0;
  582.         
  583.         //    blink the cursor
  584.         
  585.         TEIdle(theTEHandle);
  586.         
  587.         
  588.         //    try to read in any input characters from the input side of the serial port
  589.         
  590.         if (inputIsOpen == true)
  591.         {
  592.             errCode = SerGetBuf(inputRefNum,&numCharsInBuff);
  593.             
  594.             if (errCode != noErr)
  595.             {
  596.                 sprintf(errorMessage,"serialConnectToOpponents: SerGetBuf() error %d, can't determine number of bytes in serial input buffer!",(int) errCode);
  597.                 
  598.                 ErrorAlert(errorMessage);
  599.             }
  600.             
  601.             else if (numCharsInBuff > 0)
  602.             {
  603.                 if (numCharsInBuff > 255)
  604.                 {
  605.                     numCharsInBuff = 255;
  606.                 }
  607.                 
  608.                 //    queue up another read request
  609.                 
  610.                 myPBRec.ioParam.ioCompletion = (IOCompletionUPP) SerialReadCompletionRoutineASM;
  611.                 myPBRec.ioParam.ioRefNum = inputRefNum;
  612.                 myPBRec.ioParam.ioBuffer = (Ptr) tempString;
  613.                 myPBRec.ioParam.ioReqCount = numCharsInBuff;
  614.                 
  615.                 errCode = PBRead(&myPBRec,false);
  616.                 
  617.                 if (errCode != noErr)
  618.                 {
  619.                     sprintf(errorMessage,"serialConnectToOpponents: PBRead() error %d, can't read serial data!",(int) errCode);
  620.                     
  621.                     ErrorAlert(errorMessage);
  622.                 }
  623.                 
  624.                 else
  625.                 {
  626.                     srcPtr = tempString;
  627.                     destPtr = tempString;
  628.                     numCharsInBuff = 0;
  629.                     
  630.                     //    ignore linefeeds in the input stream
  631.                     
  632.                     for (i = 0;i < myPBRec.ioParam.ioActCount;i++)
  633.                     {
  634.                         if (*srcPtr == '\n')
  635.                         {
  636.                             srcPtr++;
  637.                         }
  638.                         
  639.                         else
  640.                         {
  641.                             *destPtr++ = *srcPtr++;
  642.                             numCharsInBuff++;
  643.                         }
  644.                     }
  645.                     
  646.                     //    TextEdit gets upset if we try to store more than 32K of text in a TERec
  647.                     
  648.                     if ((long) (**theTEHandle).teLength + numCharsInBuff >= 32000L)
  649.                     {
  650.                         i = 0;
  651.                         
  652.                         //    delete some lines off the top of the text
  653.                         
  654.                         while ((long) (**theTEHandle).teLength + numCharsInBuff - (long) (**theTEHandle).lineStarts[i] >= 32000L)
  655.                         {
  656.                             i++;
  657.                         }
  658.                         
  659.                         selStart = (**theTEHandle).selStart - (**theTEHandle).lineStarts[i];
  660.                         selEnd = (**theTEHandle).selEnd - (**theTEHandle).lineStarts[i];
  661.                         
  662.                         TEAutoView(false,theTEHandle);
  663.                         
  664.                         TESetSelect(0,(**theTEHandle).lineStarts[i],theTEHandle);
  665.                         TEDelete(theTEHandle);
  666.                         
  667.                         TEAutoView(true,theTEHandle);
  668.                         
  669.                         TESetSelect(selStart,selEnd,theTEHandle);
  670.                     }
  671.                     
  672.                     //    insert the characters we read in from the serial port
  673.                     
  674.                     TEInsert(tempString,numCharsInBuff,theTEHandle);
  675.                     
  676.                     TESelView(theTEHandle);
  677.                 }
  678.             }
  679.         }
  680.         
  681.         
  682.         //    check for mouse clicks and other stuff
  683.         
  684.         if (GetNextEvent(everyEvent,&theEvent) == true)
  685.         {
  686.             //    user typed something!
  687.             
  688.             if (theEvent.what == keyDown || theEvent.what == autoKey)
  689.             {
  690.                 theChar = theEvent.message & charCodeMask;
  691.                 
  692.                 if (outputIsOpen == true)
  693.                 {
  694.                     //    better send the typed character out the port....
  695.                     
  696.                     myPBRec.ioParam.ioCompletion = nil;
  697.                     myPBRec.ioParam.ioRefNum = outputRefNum;
  698.                     myPBRec.ioParam.ioBuffer = (Ptr) &theChar;
  699.                     myPBRec.ioParam.ioReqCount = 1;
  700.                     
  701.                     errCode = PBWrite(&myPBRec,false);
  702.                     
  703.                     if (errCode != noErr)
  704.                     {
  705.                         sprintf(errorMessage,"serialConnectToOpponents: PBWrite() error %d, write serial data!",(int) errCode);
  706.                         
  707.                         ErrorAlert(errorMessage);
  708.                     }
  709.                 }
  710.                 
  711.                 //    echo to screen?
  712.                 
  713.                 if (doLocalEcho == true)
  714.                 {
  715.                     TEKey(theEvent.message & charCodeMask,theTEHandle);
  716.                     
  717.                     TESelView(theTEHandle);
  718.                 }
  719.             }
  720.             
  721.             //    redraw the dialog.....
  722.             
  723.             else if (theEvent.what == updateEvt && (DialogPtr) theEvent.message == theDPtr)
  724.             {
  725.                 PenNormal();
  726.                 
  727.                 TEUpdate(&theTERect,theTEHandle);
  728.                 
  729.                 GetDItem(theDPtr, 14, &type, &theItem, &tempRect);
  730.                 FrameRect(&tempRect);
  731.                 InsetRect(&tempRect,-2,-2);
  732.                 FrameRect(&tempRect);
  733.                 
  734.                 GetDItem(theDPtr, 10, &type, &theItem, &tempRect);
  735.                 FrameRect(&tempRect);
  736.                 InsetRect(&tempRect,-2,-2);
  737.                 FrameRect(&tempRect);
  738.                 
  739.                 GetDItem(theDPtr, 15, &type, &theItem, &tempRect);
  740.                 FrameRect(&tempRect);
  741.                 InsetRect(&tempRect,-2,-2);
  742.                 FrameRect(&tempRect);
  743.                 
  744.                 GetDItem(theDPtr, 16, &type, &theItem, &tempRect);
  745.                 InsetRect(&tempRect,-2,-2);
  746.                 FrameRect(&tempRect);
  747.             }
  748.             
  749.             
  750.             //    check for event relevant to the dialog box
  751.             
  752.             if (IsDialogEvent(&theEvent) == true)
  753.             {
  754.                 if (DialogSelect(&theEvent,&tempDPtr,&itemHit) == true)
  755.                 {
  756.                     if (tempDPtr != theDPtr)
  757.                     {
  758.                         itemHit = 0;
  759.                     }
  760.                     
  761.                     else
  762.                     {
  763.                         //    deal with mouseclicks on the buttons
  764.                         
  765.                         switch(itemHit)
  766.                         {
  767.                             //    switch ports?
  768.                             
  769.                             case 12:
  770.                                 if (serialPort != MODEM)
  771.                                 {
  772.                                     CloseSerialDrivers();
  773.                                     
  774.                                     serialPort = MODEM;
  775.                                     
  776.                                     GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  777.                                     SetControlValue((ControlHandle) theItem,1);
  778.                                     GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  779.                                     SetControlValue((ControlHandle) theItem,0);
  780.                                     GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  781.                                     SetControlValue((ControlHandle) theItem,0);
  782.                                     
  783.                                     OpenSerialDrivers();
  784.                                 }
  785.                                 break;
  786.                                 
  787.                             case 13:
  788.                                 if (serialPort != PRINTER)
  789.                                 {
  790.                                     CloseSerialDrivers();
  791.                                     
  792.                                     serialPort = PRINTER;
  793.                                     
  794.                                     GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  795.                                     SetControlValue((ControlHandle) theItem,0);
  796.                                     GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  797.                                     SetControlValue((ControlHandle) theItem,1);
  798.                                     GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  799.                                     SetControlValue((ControlHandle) theItem,0);
  800.                                     
  801.                                     OpenSerialDrivers();
  802.                                 }
  803.                                 
  804.                                 break;
  805.                                 
  806.                             case 18:
  807.                                 if (serialPort != NOPORT)
  808.                                 {
  809.                                     CloseSerialDrivers();
  810.                                     
  811.                                     serialPort = NOPORT;
  812.                                     
  813.                                     GetDItem(theDPtr, 12, &type, &theItem, &tempRect);
  814.                                     SetControlValue((ControlHandle) theItem,0);
  815.                                     GetDItem(theDPtr, 13, &type, &theItem, &tempRect);
  816.                                     SetControlValue((ControlHandle) theItem,0);
  817.                                     GetDItem(theDPtr, 18, &type, &theItem, &tempRect);
  818.                                     SetControlValue((ControlHandle) theItem,1);
  819.                                 }
  820.                                 
  821.                                 break;
  822.                             
  823.                             
  824.                             //    switch speeds?
  825.                             
  826.                             case 6:
  827.                                 serialSpeed = baud19200;
  828.                                 
  829.                                 GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  830.                                 SetControlValue((ControlHandle) theItem,0);
  831.                                 GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  832.                                 SetControlValue((ControlHandle) theItem,0);
  833.                                 GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  834.                                 SetControlValue((ControlHandle) theItem,1);
  835.                                 
  836.                                 errCode = SerReset(outputRefNum,serialSpeed+data8+noParity+stop10);
  837.                                 
  838.                                 if (errCode != noErr)
  839.                                 {
  840.                                     sprintf(errorMessage,"serialConnectToOpponents: SerReset() error %d, can't set output serial port speed/data/parity/stopbits!",(int) errCode);
  841.                                     ErrorAlert(errorMessage);
  842.                                 }
  843.                                 
  844.                                 break;
  845.                                 
  846.                             case 5:
  847.                                 serialSpeed = baud9600;
  848.                                 
  849.                                 GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  850.                                 SetControlValue((ControlHandle) theItem,0);
  851.                                 GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  852.                                 SetControlValue((ControlHandle) theItem,1);
  853.                                 GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  854.                                 SetControlValue((ControlHandle) theItem,0);
  855.                                 
  856.                                 errCode = SerReset(outputRefNum,serialSpeed+data8+noParity+stop10);
  857.                                 
  858.                                 if (errCode != noErr)
  859.                                 {
  860.                                     sprintf(errorMessage,"serialConnectToOpponents: SerReset() error %d, can't set output serial port speed/data/parity/stopbits!",(int) errCode);
  861.                                     ErrorAlert(errorMessage);
  862.                                 }
  863.                                 
  864.                                 break;
  865.                                 
  866.                             case 4:
  867.                                 serialSpeed = baud2400;
  868.                                 
  869.                                 GetDItem(theDPtr, 4, &type, &theItem, &tempRect);
  870.                                 SetControlValue((ControlHandle) theItem,1);
  871.                                 GetDItem(theDPtr, 5, &type, &theItem, &tempRect);
  872.                                 SetControlValue((ControlHandle) theItem,0);
  873.                                 GetDItem(theDPtr, 6, &type, &theItem, &tempRect);
  874.                                 SetControlValue((ControlHandle) theItem,0);
  875.                                 
  876.                                 errCode = SerReset(outputRefNum,serialSpeed+data8+noParity+stop10);
  877.                                 
  878.                                 if (errCode != noErr)
  879.                                 {
  880.                                     sprintf(errorMessage,"serialConnectToOpponents: SerReset() error %d, can't set output serial port speed/data/parity/stopbits!",(int) errCode);
  881.                                     ErrorAlert(errorMessage);
  882.                                 }
  883.                                 
  884.                                 break;
  885.                             
  886.                             
  887.                             //    switch handshaking?
  888.                             
  889.                             case 8:
  890.                                 if (doXOnXOff == true)
  891.                                 {
  892.                                     doXOnXOff = false;
  893.                                     GetDItem(theDPtr, 8, &type, &theItem, &tempRect);
  894.                                     SetControlValue((ControlHandle) theItem,0);
  895.                                 }
  896.                                 
  897.                                 else
  898.                                 {
  899.                                     doXOnXOff = true;
  900.                                     GetDItem(theDPtr, 8, &type, &theItem, &tempRect);
  901.                                     SetControlValue((ControlHandle) theItem,1);
  902.                                 }
  903.                                 
  904.                                 mySerShk.fXOn = doXOnXOff;
  905.                                 mySerShk.fCTS = doHH;
  906.                                 mySerShk.xOn = 0xC1;
  907.                                 mySerShk.xOff = 0xC3;
  908.                                 mySerShk.errs = 0;
  909.                                 mySerShk.evts = 0;
  910.                                 mySerShk.fInX = doXOnXOff;
  911.                                 mySerShk.fDTR = doHH;
  912.                                 
  913.                                 errCode = Control(outputRefNum,14,&mySerShk);
  914.                                 
  915.                                 if (errCode != noErr)
  916.                                 {
  917.                                     sprintf(errorMessage,"serialConnectToOpponents: Control() error %d, can't set handshaking configuration for input/output serial port!",(int) errCode);
  918.                                     FatalError(errorMessage);
  919.                                 }
  920.                                 
  921.                                 break;
  922.                                 
  923.                             case 9:
  924.                                 if (doHH == true)
  925.                                 {
  926.                                     doHH = false;
  927.                                     GetDItem(theDPtr, 9, &type, &theItem, &tempRect);
  928.                                     SetControlValue((ControlHandle) theItem,0);
  929.                                 }
  930.                                 
  931.                                 else
  932.                                 {
  933.                                     doHH = true;
  934.                                     GetDItem(theDPtr, 9, &type, &theItem, &tempRect);
  935.                                     SetControlValue((ControlHandle) theItem,1);
  936.                                 }
  937.                                 
  938.                                 mySerShk.fXOn = doXOnXOff;
  939.                                 mySerShk.fCTS = doHH;
  940.                                 mySerShk.errs = 0;
  941.                                 mySerShk.evts = 0;
  942.                                 mySerShk.fInX = doXOnXOff;
  943.                                 mySerShk.fDTR = doHH;
  944.                                 
  945.                                 errCode = Control(outputRefNum,14,&mySerShk);
  946.                                 
  947.                                 if (errCode != noErr)
  948.                                 {
  949.                                     sprintf(errorMessage,"serialConnectToOpponents: Control() error %d, can't set handshaking configuration for input/output serial port!",(int) errCode);
  950.                                     FatalError(errorMessage);
  951.                                 }
  952.                                 
  953.                                 break;
  954.                             
  955.                             
  956.                             //    turn on/off local echo?
  957.                             
  958.                             case 17:
  959.                                 if (doLocalEcho == true)
  960.                                 {
  961.                                     doLocalEcho = false;
  962.                                     
  963.                                     GetDItem(theDPtr, 17, &type, &theItem, &tempRect);
  964.                                     SetControlValue((ControlHandle) theItem,0);
  965.                                 }
  966.                                 
  967.                                 else
  968.                                 {
  969.                                     doLocalEcho = true;
  970.                                     
  971.                                     GetDItem(theDPtr, 17, &type, &theItem, &tempRect);
  972.                                     SetControlValue((ControlHandle) theItem,1);
  973.                                 }
  974.                                 
  975.                                 break;
  976.                                 
  977.                             default:
  978.                                 SysBeep(1);
  979.                         }
  980.                     }
  981.                 }
  982.                 
  983.                 else
  984.                 {
  985.                     itemHit = 0;
  986.                 }
  987.             }
  988.         }
  989.         
  990.     } while (itemHit != 1 && itemHit != 2);
  991.     
  992.     
  993.     //    user clicked "Okay" button!
  994.     
  995.     if (itemHit == 1)
  996.     {
  997.         if (inputIsOpen == true)
  998.         {
  999.             //    get ready for asynch serial reads....
  1000.             
  1001.             initSerialReadCompletionRoutine();
  1002.             
  1003.             
  1004.             //    tell the asynch completion routine it's okay to queue up more read requests
  1005.             
  1006.             doAsynchReceives = true;
  1007.             
  1008.             
  1009.             //    queue up that first asynch read!
  1010.             
  1011.             myReadPB.ioParam.ioCompletion = (IOCompletionUPP) SerialReadCompletionRoutineASM;
  1012.             myReadPB.ioParam.ioRefNum = inputRefNum;
  1013.             myReadPB.ioParam.ioBuffer = serialPacketBuffer;
  1014.             myReadPB.ioParam.ioReqCount = sizeof(GameData) + 1;
  1015.             
  1016.             errCode = PBRead(&myReadPB,true);
  1017.             
  1018.             if (errCode != noErr)
  1019.             {
  1020.                 sprintf(errorMessage,"serialConnectToOpponents: PBRead() error %d, can't start asynch read of serial data!",(int) errCode);
  1021.                 
  1022.                 ErrorAlert(errorMessage);
  1023.             }
  1024.         }
  1025.     }
  1026.     
  1027.     //    user doesn't want to play
  1028.     
  1029.     else if (itemHit == 2)
  1030.     {
  1031.         CloseSerialDrivers();
  1032.         
  1033.         errCode = SERIALCONNECTCANCELLED;
  1034.     }
  1035.     
  1036. EXITPOINT:
  1037.     
  1038.     if (theTEHandle)
  1039.     {
  1040.         TEDispose(theTEHandle);
  1041.     }
  1042.     
  1043.     if (theDPtr != nil)
  1044.     {
  1045.         DisposDialog(theDPtr);
  1046.     }
  1047.     
  1048.     if (oldPort != nil)
  1049.     {
  1050.         SetPort(oldPort);
  1051.     }
  1052.     
  1053.     return(errCode);
  1054. }
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060. //    Completion routine for asynch reads
  1061.  
  1062. static void SerialReceiveCompletionC(void)
  1063. {
  1064. OSErr    errCode;
  1065. register unsigned char        *srcBytePtr,*destBytePtr;
  1066. register long                numBytesToProcess;
  1067.  
  1068.  
  1069.     //    figure out how much data we have to work with and where it is
  1070.         
  1071.     srcBytePtr = (unsigned char *) serialPacketBuffer + numBytesInPacketBuff;
  1072.     destBytePtr = (unsigned char *) serialPacketBuffer + numBytesInPacketBuff;
  1073.     numBytesToProcess = myReadPB.ioParam.ioActCount;
  1074.     
  1075.     
  1076.     while (numBytesToProcess > 0)
  1077.     {
  1078.         //    watch out for packet end markers....
  1079.         
  1080.         if (*srcBytePtr == ENDPACKETCHAR)
  1081.         {
  1082.             srcBytePtr++;
  1083.             numBytesToProcess--;
  1084.             
  1085.             if (numBytesToProcess == 0)
  1086.             {
  1087.                 break;    /* We're done or the break occurred on the border */
  1088.             }
  1089.             
  1090.             else if (*srcBytePtr != ENDPACKETCHAR)
  1091.             {
  1092.                 //    oops-- bad packet-- junk it all
  1093.                 
  1094.                 numBytesInPacketBuff = 0;
  1095.                 destBytePtr = (unsigned char *) serialPacketBuffer;
  1096.             }
  1097.         }
  1098.         
  1099.         
  1100.         //    copy bytes to destination, now that we have stripped out the packet framing characters
  1101.         
  1102.         *destBytePtr++ = *srcBytePtr++;
  1103.         numBytesToProcess--;
  1104.         numBytesInPacketBuff++;
  1105.     }
  1106.     
  1107.     
  1108.     //    have we read a complete data packet?  if there's more than one, only use the latest....
  1109.     
  1110.     while (numBytesInPacketBuff >= sizeof(GameData))
  1111.     {
  1112.         gameReceiveBroadcastData(serialPacketBuffer,(long) sizeof(GameData));
  1113.         
  1114.         BlockMove(serialPacketBuffer + sizeof(GameData),serialPacketBuffer,numBytesInPacketBuff - sizeof(GameData));
  1115.         
  1116.         numBytesInPacketBuff -= sizeof(GameData);
  1117.     }
  1118.  
  1119.     
  1120.     //    should we try to read more data?
  1121.     
  1122.     if (doAsynchReceives == true)
  1123.     {
  1124.         myReadPB.ioParam.ioCompletion = (IOCompletionUPP) SerialReadCompletionRoutineASM;
  1125.         myReadPB.ioParam.ioRefNum = inputRefNum;
  1126.         myReadPB.ioParam.ioBuffer = serialPacketBuffer + numBytesInPacketBuff;
  1127.         myReadPB.ioParam.ioReqCount = sizeof(GameData) + 1 - numBytesInPacketBuff;
  1128.         
  1129.         errCode = PBRead(&myReadPB,true);
  1130.         
  1131.         if (errCode != noErr)
  1132.         {
  1133.             
  1134.         }
  1135.     }
  1136. }
  1137.  
  1138.  
  1139.  
  1140. //    The assembly language glue routine that gets called when an asynch read completes, and in turn calls the "C" version handler
  1141.  
  1142. static asm void mySerialCompletionASMCode(void)
  1143. {
  1144.         rts        //    bozo-proof the routine in case someone tries to just call mySerialCompletionASMCode()
  1145.     
  1146. myA5:    dc.l    0    //    storage for A5 so we can access application globals later
  1147.  
  1148.  
  1149.     //    routine to initialize asynch handling-- simply saves A5 for later use
  1150.     
  1151. ENTRY    static    initSerialReadCompletionRoutine
  1152.         
  1153.         movem.l        A3,-(A7)
  1154.         
  1155.         lea            myA5,A3
  1156.         movem.l        A5,(A3)
  1157.         
  1158.         movem.l        (A7)+,A3
  1159.         
  1160.         rts
  1161.  
  1162.     //    the actual completion routine!
  1163.             
  1164. ENTRY    static    SerialReadCompletionRoutineASM
  1165.         
  1166.         movem.l        D3-D7/A2-A6,-(A7)    //    save registers
  1167.         
  1168.         lea            myA5,A3        //    get A5
  1169.         movem.l        (A3),A5
  1170.  
  1171.         jsr            SerialReceiveCompletionC    //    call the high-level handler
  1172.         
  1173.         movem.l        (A7)+,D3-D7/A2-A6    //    restore registers!
  1174.  
  1175. @EXIT:    rts
  1176. }
  1177.  
  1178.  
  1179.  
  1180.  
  1181. //    routine called to send a data packet
  1182.  
  1183. void serialSendData(Ptr theDataPtr,long theDataLength)
  1184. {
  1185. OSErr                        errCode;
  1186. register unsigned char        *srcBytePtr,*destBytePtr;
  1187. register long                srcbyteCount,destByteCount;
  1188.  
  1189.     // a quick reality check to be sure the output driver is open and the last write has completed
  1190.     
  1191.     if (outputIsOpen == true && myWritePB.ioParam.ioResult != 1)
  1192.     {
  1193.         errCode = myWritePB.ioParam.ioResult;
  1194.         
  1195.         if (errCode != noErr)
  1196.         {
  1197.             sprintf(errorMessage,"serialSendData: PBWrite() error %d, asynch send of serial data was unsuccessful!",(int) errCode);
  1198.             
  1199.             ErrorAlert(errorMessage);
  1200.         }
  1201.         
  1202.         
  1203.         //    copy the data and add packet framing characters, also double up any occurrence of the framing characters to avoid confusing the sendee....
  1204.                 
  1205.         srcBytePtr = (unsigned char *) theDataPtr;
  1206.         destBytePtr = (unsigned char *) serialOutputBufferPtr;
  1207.         srcbyteCount = 0;
  1208.         destByteCount = 0;
  1209.         
  1210.         while (srcbyteCount < theDataLength)
  1211.         {
  1212.             if (*srcBytePtr == ENDPACKETCHAR)
  1213.             {
  1214.                 *destBytePtr++ = ENDPACKETCHAR;
  1215.                 destByteCount++;
  1216.             }
  1217.             
  1218.             *destBytePtr++ = *srcBytePtr++;
  1219.             srcbyteCount++;
  1220.             destByteCount++;
  1221.         }
  1222.         
  1223.         *destBytePtr = ENDPACKETCHAR;
  1224.         destByteCount++;
  1225.         
  1226.         
  1227.         //    now send it!
  1228.         
  1229.         myWritePB.ioParam.ioCompletion = nil;
  1230.         myWritePB.ioParam.ioRefNum = outputRefNum;
  1231.         myWritePB.ioParam.ioBuffer = serialOutputBufferPtr;
  1232.         myWritePB.ioParam.ioReqCount = (short) destByteCount;
  1233.         
  1234.         errCode = PBWrite(&myWritePB,true);
  1235.         
  1236.         if (errCode != noErr)
  1237.         {
  1238.             sprintf(errorMessage,"serialSendData: PBWrite() error %d, can't start asynch send of serial data!",(int) errCode);
  1239.             
  1240.             ErrorAlert(errorMessage);
  1241.         }
  1242.     }
  1243. }
  1244.